//
// Created by Ge on 2024/3/6.
// 小模型为网格（Mesh）
//
#include "include/a3d/Mesh.h"
#include "include/a3d/Model.h"
#include "include/assimp/scene.h"
#include "string"
#include "include/assimp/Importer.hpp"
#include "include/assimp/postprocess.h"

void Mesh::draw() {

}

void Mesh::destroy() {

}

void Mesh::setupMesh() {

}

void Model::draw() {

}

void Model::destroy() {

}

void Model::loadModel(std::string path) {
    Assimp::Importer importer;
    const aiScene *scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs |
                                                   aiProcess_CalcTangentSpace);
    // 出错则返回
    if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) // if is Not Zero
    {
        return;
    }
    //遍历节点
    processNode(scene->mRootNode, scene);
}

void Model::processNode(aiNode *node, const aiScene *scene) {
    // 遍历当前node的mesh数组
    for (unsigned int i = 0; i < node->mNumMeshes; i++) {
        //根据数组存的index，从scene拿到原始的aiMesh
        aiMesh *mesh = scene->mMeshes[node->mMeshes[i]];
        if (mesh != nullptr)
            meshes.push_back(processMesh(mesh, scene));//处理mesh数据，具体见下一个函数
    }
    // 遍历子节点
    for (unsigned int i = 0; i < node->mNumChildren; i++) {
        processNode(node->mChildren[i], scene);
    }
}

//生成网格
Mesh Model::processMesh(aiMesh *mesh, const aiScene *scene) {
// data to fill
    std::vector <Vertex> vertices;
    std::vector<unsigned int> indices;
    std::vector <Texture> textures;
    // Walk through each of the mesh's vertices
    for (unsigned int i = 0; i < mesh->mNumVertices; i++) {
        Vertex vertex;
        glm::vec3 vector; //把assimp的坐标格式转换为glm::vec3，方便openGL读取
        // 顶点坐标
        vector.x = mesh->mVertices[i].x;
        vector.y = mesh->mVertices[i].y;
        vector.z = mesh->mVertices[i].z;
        vertex.position = vector;
        updateMaxMinXyz(vector);
        // 法线坐标
        vector.x = mesh->mNormals[i].x;
        vector.y = mesh->mNormals[i].y;
        vector.z = mesh->mNormals[i].z;
        vertex.normal = vector;
        // 纹理坐标
        if (mesh->mTextureCoords[0]) // does the mesh contain texture coordinates?
        {
            glm::vec2 vec;
            // 顶点最多可以指向8个纹理坐标，但一般只有一个
            vec.x = mesh->mTextureCoords[0][i].x;
            vec.y = mesh->mTextureCoords[0][i].y;
            vertex.texCoords = vec;
        } else
            vertex.texCoords = glm::vec2(0.0f, 0.0f);

        // 切线
        vector.x = mesh->mTangents[i].x;
        vector.y = mesh->mTangents[i].y;
        vector.z = mesh->mTangents[i].z;
        vertex.tangent = vector;
        // 双切线
        vector.x = mesh->mBitangents[i].x;
        vector.y = mesh->mBitangents[i].y;
        vector.z = mesh->mBitangents[i].z;
        vertex.tangent = vector;
        vertices.push_back(vertex);
    }
    // 遍历所有的面，即三角形
    for (unsigned int i = 0; i < mesh->mNumFaces; i++) {
        aiFace face = mesh->mFaces[i];
        // 检索一个面的顶点索引，并存到indices变量
        for (unsigned int j = 0; j < face.mNumIndices; j++)
            indices.push_back(face.mIndices[j]);
    }
    // 开始处理网格锁使用的材质
    aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex];
    //遍历各种类型的纹理，根据不同的类型，耶规范纹理名称，后面的shader会使用这种纹理名称
    // 例如所有漫反射纹理，在shader中的名字为'texture_diffuseN', N 从1 到 MAX_SAMPLER_NUMBER.
    // 其他的类型耶类似
    // diffuse: texture_diffuseN
    // specular: texture_specularN
    // normal: texture_normalN
    // 1. diffuse maps
    std::vector <Texture> diffuseMaps = loadMaterialTextures(material, aiTextureType_DIFFUSE,
                                                        "texture_diffuse");
    textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
    // 2. specular maps
    std::vector <Texture> specularMaps = loadMaterialTextures(material, aiTextureType_SPECULAR,
                                                         "texture_specular");
    textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
    // 3. normal maps
    std::vector<Texture> normalMaps = loadMaterialTextures(material, aiTextureType_HEIGHT,
                                                           "texture_normal");
    textures.insert(textures.end(), normalMaps.begin(), normalMaps.end());
    // 4. height maps
    std::vector<Texture> heightMaps = loadMaterialTextures(material, aiTextureType_AMBIENT,
                                                           "texture_height");
    textures.insert(textures.end(), heightMaps.begin(), heightMaps.end());
    // 最后生成了一个纹理，包含了坐标和纹理数据
    return Mesh(vertices, indices, textures);
}

//创建纹理并加载图像数据
std::vector<Texture>
Model::loadMaterialTextures(aiMaterial *mat, aiTextureType type, std::string typeName) {

}
